package chen.huai.jie.spring.xmlconfig.mybatis;

import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Properties;

@Component
@Intercepts({@Signature(
        type = StatementHandler.class,
        method = "prepare",
        args = {Connection.class, Integer.class}
)})
public class PageInterceptor implements Interceptor {
    private final Logger logger = LoggerFactory.getLogger(PageInterceptor.class);

    public PageInterceptor() {
    }

    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        ParameterHandler parameterHandler = (ParameterHandler) metaObject.getValue("parameterHandler");
        Object parameterObject = parameterHandler.getParameterObject();
        PageRequest pageRequest = null;
        if (parameterObject instanceof MapperMethod.ParamMap) {
            MapperMethod.ParamMap paramMapObject = (MapperMethod.ParamMap) parameterObject;
            Iterator var8 = paramMapObject.keySet().iterator();

            while (var8.hasNext()) {
                Object key = var8.next();
                if (paramMapObject.get(key) instanceof PageRequest) {
                    pageRequest = (PageRequest) paramMapObject.get(key);
                    break;
                }
            }
        } else if (parameterObject instanceof PageRequest) {
            pageRequest = (PageRequest) parameterObject;
        }

        if (pageRequest != null) {
            BoundSql boundSql = (BoundSql) metaObject.getValue("parameterHandler.boundSql");
            String originalSql = boundSql.getSql();
            String countSql = "select count(1) " + originalSql.substring(originalSql.indexOf("FROM"));
            Connection connection = (Connection) invocation.getArgs()[0];
            MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
            long total = this.getTotal(countSql, connection, mappedStatement, boundSql);
            pageRequest.context = total;
            if (total == 0L) {
                return invocation.proceed();
            } else {
                StringBuilder pageSqlBuilder = new StringBuilder(originalSql);
                if (pageRequest.getOrderBy() != null && !pageRequest.getOrderBy().isEmpty()) {
                    pageSqlBuilder.append(" order by ").append(pageRequest.getOrderBy()).append(pageRequest.isAsc() ? " asc" : " desc");
                }

                int offset = 0;
                if (pageRequest.getCurrent() > 0) {
                    offset = pageRequest.getSize() * (pageRequest.getCurrent() - 1);
                }

                pageSqlBuilder.append(" limit ").append(offset).append(",").append(pageRequest.getSize());
                metaObject.setValue("delegate.boundSql.sql", pageSqlBuilder.toString());
                return invocation.proceed();
            }
        } else {
            return invocation.proceed();
        }
    }

    private long getTotal(String sql, Connection connection, MappedStatement mappedStatement, BoundSql boundSql) {
        PreparedStatement preparedStmt = null;
        ResultSet rs = null;

        try {
            preparedStmt = connection.prepareStatement(sql);
            BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), sql, boundSql.getParameterMappings(), boundSql.getParameterObject());
            ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, boundSql.getParameterObject(), countBS);
            parameterHandler.setParameters(preparedStmt);
            rs = preparedStmt.executeQuery();
            long total = 0L;
            if (rs.next()) {
                total = rs.getLong(1);
            }

            long var11 = total;
            return var11;
        } catch (SQLException var22) {
            this.logger.error("Find result count error", var22);
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }

                if (preparedStmt != null) {
                    preparedStmt.close();
                }
            } catch (SQLException var21) {
                this.logger.error("Find result count error", var21);
            }

        }

        return 0L;
    }

    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    public void setProperties(Properties properties) {
    }
}
